package collector

import (
	"context"
	"github.com/go-kit/kit/log"
	"github.com/go-redis/redis/v8"
	"github.com/prometheus/client_golang/prometheus"
)

// 内存指标
// used_memory 已使用内存
// mem_fragmentation_ratio 内存碎片率
// evicted_keys  由于最大内存限制被移除的key数量
// blocked_clients 被阻塞的客户端
const (
	// Subsystem.
	memory                = "memory"
	usedMemory            = "used_memory"
	memFragmentationRatio = "mem_fragmentation_ratio"
	evictedKeys           = "evicted_keys"
	blockedClients        = "blocked_clients"
)

// Metric descriptors.
var (
	usedMemoryDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, memory, usedMemory),
		"已使用内存",
		[]string{}, nil,
	)
	memFragmentationRatioDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, memory, memFragmentationRatio),
		"内存碎片率",
		[]string{}, nil,
	)
	evictedKeysDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, memory, evictedKeys),
		"由于最大内存限制被移除的key数量（秒）",
		[]string{}, nil,
	)
	blockedClientsDesc = prometheus.NewDesc(
		prometheus.BuildFQName(namespace, memory, blockedClients),
		"被阻塞的客户端",
		[]string{}, nil,
	)
)

// ScrapeMemory collects from performance.
type ScrapeMemory struct{}

// Name of the Scraper. Should be unique.
func (ScrapeMemory) Name() string {
	return memory
}

// Help describes the role of the Scraper.
func (ScrapeMemory) Help() string {
	return "Collect the current size of all registered binlog files"
}

// Version of Redis from which scraper is available.
func (ScrapeMemory) Version() float64 {
	return 4.0
}

// Scrape collects data from redis connection and sends it over channel as prometheus metric.
func (ScrapeMemory) Scrape(ctx context.Context, client *redis.Client, ch chan<- prometheus.Metric, logger log.Logger) error {

	data, err := infos(client, "memory", "stats", "clients")
	if err != nil {
		return err
	}

	used := valueOf(data, usedMemory)
	frag := valueOf(data, memFragmentationRatio)
	evicted := valueOf(data, evictedKeys)
	blocked := valueOf(data, blockedClients)

	ch <- prometheus.MustNewConstMetric(
		usedMemoryDesc, prometheus.GaugeValue, used,
	)
	ch <- prometheus.MustNewConstMetric(
		memFragmentationRatioDesc, prometheus.GaugeValue, frag,
	)

	ch <- prometheus.MustNewConstMetric(
		evictedKeysDesc, prometheus.GaugeValue, evicted,
	)

	ch <- prometheus.MustNewConstMetric(
		blockedClientsDesc, prometheus.GaugeValue, blocked,
	)

	return nil
}

// check interface
var _ Scraper = ScrapeMemory{}
